Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

73장. 동기 vs 비동기 — 무엇을 어디에 쓰는가

이 장에서 말하고자 하는 것

마이크로서비스가 늘어나면 서비스끼리 부르는 일이 잦아진다.

orders 서비스 → users 서비스 (사용자 정보 조회)
orders 서비스 → payments 서비스 (결제 처리)
orders 서비스 → notification 서비스 (주문 알림)

이때 호출 방식이 두 가지로 나뉜다.

  • 동기 (Synchronous) — 답을 기다린다
  • 비동기 (Asynchronous) — 메시지만 던지고 다음으로 간다

이 선택이 시스템의 결합도와 안정성을 결정한다.


1. 동기 호출

orders → "u-1 사용자 정보 줘" → users
        ← (응답 기다림)
        ← 사용자 정보
  • 단순하다
  • 실시간 응답이 필요할 때 자연스럽다
  • 호출 대상이 죽어 있으면 나도 영향받는다

REST · gRPC · GraphQL 호출이 모두 동기다.


2. 비동기 호출

orders → "주문 생성됨" → 메시지 큐
                          ↓ (시간차)
                       notification 서비스가 꺼내서 처리
  • orders는 응답을 기다리지 않는다
  • notification 서비스가 잠깐 죽어도 orders는 영향 없음
  • 처리에 시간차가 있다 (보통 ms~수 초)

3. 어떤 걸 골라야 하는가

동기가 어울리는 경우

  • 사용자에게 즉시 응답해야 함
  • 결과를 기다려야 다음 단계 진행이 가능
  • 강한 일관성이 필요
"내 프로필 보여줘"  → 동기
"이 주문 결제됐어?" → 동기

비동기가 어울리는 경우

  • 보내고 다음으로 가도 됨
  • 받는 쪽이 느려도 보내는 쪽은 빨라야 함
  • 여러 서비스에 같은 사건을 알리고 싶음
"주문 생성됨" → 알림 / 분석 / 추천 등 여러 곳으로
"이미지 업로드됨" → 썸네일 생성 / 분석 / 검열

4. 비동기가 풀어주는 결합도

같은 일을 동기로 묶으면 이렇게 된다.

orders → users
       → payments
       → notification
       → analytics
       → recommendation
  • 어느 한 서비스가 느려지면 orders 응답이 느려진다
  • 어느 한 서비스가 죽으면 orders 도 실패
  • 새 서비스를 끼우려면 orders 코드 수정 필요

비동기로 풀면

orders → 메시지 발행 (한 곳)
            ↓
       여러 서비스가 각자 받음
  • orders는 단 한 번만 보낸다
  • 새 서비스를 끼우려면 그 서비스가 구독하면 끝
  • 한 서비스 장애가 다른 서비스에 안 번진다

5. AWS의 비동기 도구들

도구모델핵심 용도
SQS큐 (1:1)작업 큐, 워커 패턴
SNS토픽 (1:N)팬아웃, 알림
EventBridge이벤트 버스 (라우팅)이벤트 기반 아키텍처, 서드파티 통합
Kinesis스트림대량 실시간 처리
MSK / MQKafka / RabbitMQ복잡한 라우팅, 외부 호환

각자 다음 장들에서 자세히 본다.


6. 동기와 비동기는 한 시스템에서 같이 산다

실제 운영은 둘을 섞는다.

사용자 → orders (동기)
         ↓
       "주문 생성됨" 이벤트 발행 (비동기)
         ↓
       notification · analytics · recommendation 받음

외부와의 접점은 동기, 내부 부수 효과는 비동기

이게 가장 흔한 패턴이다.


7. 우리 서비스에서

[사용자] → [API Gateway] → [ALB] → [orders]     ← 동기 (응답 필요)
                                       ↓
                                   "OrderCreated" 이벤트
                                       ↓ (비동기)
                                   ┌─ notification ─ 알림
                                   ├─ analytics    ─ 통계
                                   └─ inventory    ─ 재고 차감

orders는 한 번만 발행하고, 받는 쪽은 각자 처리한다.


8. 직접 확인해보기 — 의사 결정 가이드

새 호출이 필요해질 때 다음 질문을 던진다.

"호출자가 응답이 없으면 다음 단계를 못 가나?"
  └─ Yes → 동기
  └─ No  → 비동기

"여러 서비스가 같은 사건을 알아야 하나?"
  └─ Yes → 비동기 (SNS · EventBridge)

"보내는 쪽이 받는 쪽 가용성에 묶이면 곤란한가?"
  └─ Yes → 비동기 (SQS)

9. 코드로는 이렇게 생겼다 — 발행자 예 (Node.js)

import { SNSClient, PublishCommand } from "@aws-sdk/client-sns";

const sns = new SNSClient({ region: "ap-northeast-2" });

async function publishOrderCreated(order) {
  await sns.send(new PublishCommand({
    TopicArn: process.env.ORDER_EVENTS_TOPIC,
    Message: JSON.stringify({
      type: "OrderCreated",
      orderId: order.id,
      userId: order.userId,
      total: order.total,
    }),
  }));
}

orders는 누가 받는지 모른다 — 토픽에 던지기만 하면 끝.


10. 이렇게 쓰면 망한다 — 안티패턴

안티패턴 1. 모든 호출을 동기로 만든다

시스템이 결합도 폭탄이 된다. 한 서비스 장애가 모두에 번진다.

안티패턴 2. 모든 호출을 비동기로 만든다

사용자가 결과를 기다려야 하는 흐름이 어색해진다.
응답에 즉시 결과를 줘야 하는 곳에는 동기가 맞다.

안티패턴 3. 비동기에 정확한 응답 시간을 기대한다

비동기는 본질적으로 시간차가 있다.

“5초 안에 처리됨” 같은 보장은 비동기로 만들기 어렵다

안티패턴 4. 메시지를 받지 못해도 시스템이 알아채지 못한다

DLQ (Dead Letter Queue) · 알람 없이는 메시지 손실을 모른다.


11. 한 줄로 정리

동기는 답을 기다리고, 비동기는 메시지를 던진다.
외부 접점은 동기, 내부 부수 효과는 비동기 — 이 조합이 운영의 기본이다


12. 이 장의 핵심 정리

  1. 동기는 즉시 응답, 비동기는 시간차 처리다.
  2. 비동기는 결합도를 낮추고 장애 전염을 막는다.
  3. 한 시스템에서 둘은 함께 산다 — 자리에 맞춰 고른다.
  4. AWS는 SQS · SNS · EventBridge · Kinesis 등 비동기 도구를 풍부하게 제공한다.
  5. 비동기에는 시간차가 본질이다 — 즉각 응답을 기대하지 않는다.